// +FHDR----------------------------------------------------------
// Copyright (c) 2023, RJMicro Technology Co.,Ltd.
// RJMicro Confidential Proprietary
// ---------------------------------------------------------------
// FILE NAME       : .v
// DEPARTMENT      : IC Dept
// AUTHOR          :
// AUTHOR'S EMAIL  :
// ---------------------------------------------------------------
//
// Description     :
// 12'h000  MODER
// 12'h004  OTYPER
// 12'h008  STR
// 12'h00C  SLEWR
// 12'h010  PUPDR
// 12'h01C  IDR
// 12'h020  ODR
// 12'h024  AFLR
// 12'h028  AFHR
// 12'h040  EDGIER
// 12'h044  EDGISR
// 12'h060  EDGICLR
// 12'h070  LEVIER
// 12'h074  LEVISR
// 12'h080  LEVICLR
// -FHDR
// ---------------------------------------------------------------

module gpioa_regfile (
    output [31:0]          moder               ,
    output [15:0]          otyper              ,
    output [15:0]          str                 ,
    output [15:0]          slewr               ,
    output [31:0]          pupdr               ,
    input  [15:0]          idr                 ,
    output [15:0]          odr                 ,
    output [31:0]          aflr                ,
    output [31:0]          afhr                ,
    output [31:0]          edgier              ,
    input  [31:0]          edgisr              ,
    output [31:0]          edgiclr             ,
    output [31:0]          levier              ,
    input  [31:0]          levisr              ,
    output [31:0]          leviclr             ,
    input                  hclk                ,
    input                  hrstn               ,

    input                  hready              ,
    input  [31:0]          haddr               ,
    input                  hwrite              ,
    input  [01:0]          htrans              ,
    input  [02:0]          hsize               ,
    input  [31:0]          hwdataa              ,

//   output                 hreadyout           ,
//   output                 hreadyout_peri      ,
    input                   hsel_gpioa          ,
    output [31:0]           hrdata_gpioa
);

// ------------------------------------------------------------
// AHB write read enable
// ------------------------------------------------------------
wire            ahb_cs    = hsel_gpioa & hready & htrans[1];
wire            read_en   = ahb_cs & (~hwrite);
reg     [11:2]  addr;
reg             write_en;
reg     [31:0]  ff_rdata;

always @(posedge hclk or negedge hrstn) begin
    if (~hrstn) begin
        addr      <= 6'h0;
        write_en  <= 1'h0;
    end else begin
        addr      <= haddr[11:2];
        write_en  <= ahb_cs & (~hwrite);
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        hrdata_gpioa <= 32'b0;
    else if (read_en) 
        hrdata_gpioa <= ff_rdata[31:0];
end

// ------------------------------------------------------------
// Internal Signals
// ------------------------------------------------------------
reg     [31:0]  ff_moder            ;
reg     [15:0]  ff_otyper           ;
reg     [15:0]  ff_str              ;
reg     [15:0]  ff_slewr            ;
reg     [31:0]  ff_pupdr            ;
reg     [15:0]  ff_odr              ;
reg     [31:0]  ff_aflr             ;
reg     [31:0]  ff_afhr             ;
reg     [31:0]  ff_edgier           ;
reg     [31:0]  ff_edgiclr          ;
reg     [31:0]  ff_levier           ;
reg     [31:0]  ff_leviclr          ;

wire    [15:0]  wir_idr             ;
wire    [31:0]  wir_edgisr          ;
wire    [31:0]  wir_levisr          ;
assign          wir_idr             = idr[15:0]           ;
assign          wir_edgisr          = edgisr[31:0]        ;
assign          wir_levisr          = levisr[31:0]        ;

// ------------------------------------------------------------
// write_process
// ------------------------------------------------------------
wire     wren_moder          = write_en & (addr[11:2] == 10'h0);
wire     wren_otyper         = write_en & (addr[11:2] == 10'h1);
wire     wren_str            = write_en & (addr[11:2] == 10'h2);
wire     wren_slewr          = write_en & (addr[11:2] == 10'h3);
wire     wren_pupdr          = write_en & (addr[11:2] == 10'h4);
wire     wren_odr            = write_en & (addr[11:2] == 10'h8);
wire     wren_aflr           = write_en & (addr[11:2] == 10'h9);
wire     wren_afhr           = write_en & (addr[11:2] == 10'ha);
wire     wren_edgier         = write_en & (addr[11:2] == 10'h10);
wire     wren_edgiclr        = write_en & (addr[11:2] == 10'h18);
wire     wren_levier         = write_en & (addr[11:2] == 10'h1c);
wire     wren_leviclr        = write_en & (addr[11:2] == 10'h20);

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_moder <= 32'ha000;
    else if (wren_moder) begin
        ff_moder <= wdata[31:0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_otyper <= 16'h0;
    else if (wren_otyper) begin
        ff_otyper <= wdata[15:0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_str <= 16'h0;
    else if (wren_str) begin
        ff_str <= wdata[15:0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_slewr <= 16'h0;
    else if (wren_slewr) begin
        ff_slewr <= wdata[15:0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_pupdr <= 32'h55559555;
    else if (wren_pupdr) begin
        ff_pupdr <= wdata[31:0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_odr <= 16'h0;
    else if (wren_odr) begin
        ff_odr <= wdata[15:0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_aflr <= 32'h0;
    else if (wren_aflr) begin
        ff_aflr <= wdata[31:0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_afhr <= 32'h0;
    else if (wren_afhr) begin
        ff_afhr <= wdata[31:0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_edgier <= 32'h0;
    else if (wren_edgier) begin
        ff_edgier <= wdata[31:0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_edgiclr <= 32'h0;
    else if (wren_edgiclr)
        ff_edgiclr <= wdata[31:0];
    else 
        ff_edgiclr <= 32'h0;
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_levier <= 32'h0;
    else if (wren_levier) begin
        ff_levier <= wdata[31:0];
    end
end

always @(posedge hclk or negedge hrstn) begin
    if (!hrstn)
        ff_leviclr <= 32'h0;
    else if (wren_leviclr)
        ff_leviclr <= wdata[31:0];
    else 
        ff_leviclr <= 32'h0;
end


// ------------------------------------------------------------
// read_process
// ------------------------------------------------------------

wire  [31:0]  wir_r_moder    = {ff_moder[31:0]};
wire  [31:0]  wir_r_otyper   = {16'h0, ff_otyper[15:0]};
wire  [31:0]  wir_r_str      = {16'h0, ff_str[15:0]};
wire  [31:0]  wir_r_slewr    = {16'h0, ff_slewr[15:0]};
wire  [31:0]  wir_r_pupdr    = {ff_pupdr[31:0]};
wire  [31:0]  wir_r_idr      = {16'h0, wir_idr[15:0]};
wire  [31:0]  wir_r_odr      = {16'h0, ff_odr[15:0]};
wire  [31:0]  wir_r_aflr     = {ff_aflr[31:0]};
wire  [31:0]  wir_r_afhr     = {ff_afhr[31:0]};
wire  [31:0]  wir_r_edgier   = {ff_edgier[31:0]};
wire  [31:0]  wir_r_edgisr   = {wir_edgisr[31:0]};
wire  [31:0]  wir_r_levier   = {ff_levier[31:0]};
wire  [31:0]  wir_r_levisr   = {wir_levisr[31:0]};

always @ (*) begin
    ff_rdata = 32'h0;
    if (read_en) begin
        case (addr[11:2])
            10'b0000000000     :    ff_rdata = wir_r_moder;
            10'b0000000001     :    ff_rdata = wir_r_otyper;
            10'b0000000010     :    ff_rdata = wir_r_str;
            10'b0000000011     :    ff_rdata = wir_r_slewr;
            10'b0000000100     :    ff_rdata = wir_r_pupdr;
            10'b0000000111     :    ff_rdata = wir_r_idr;
            10'b0000001000     :    ff_rdata = wir_r_odr;
            10'b0000001001     :    ff_rdata = wir_r_aflr;
            10'b0000001010     :    ff_rdata = wir_r_afhr;
            10'b0000010000     :    ff_rdata = wir_r_edgier;
            10'b0000010001     :    ff_rdata = wir_r_edgisr;
            10'b0000011100     :    ff_rdata = wir_r_levier;
            10'b0000011101     :    ff_rdata = wir_r_levisr;
            default: ff_rdata = 32'h0;
        endcase
    end
end
// ------------------------------------------------------------
// Assign
// ------------------------------------------------------------
assign  moder               = ff_moder            ;
assign  otyper              = ff_otyper           ;
assign  str                 = ff_str              ;
assign  slewr               = ff_slewr            ;
assign  pupdr               = ff_pupdr            ;
assign  odr                 = ff_odr              ;
assign  aflr                = ff_aflr             ;
assign  afhr                = ff_afhr             ;
assign  edgier              = ff_edgier           ;
assign  edgiclr             = ff_edgiclr          ;
assign  levier              = ff_levier           ;
assign  leviclr             = ff_leviclr          ;
// ------------------------------------------------------------
// End of the module
// ------------------------------------------------------------
endmodule
